<?php

namespace app\db\model;

use think\Db;
use think\Model;
use think\Cache;

class DbTemplate extends Model
{

    // 开启自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    protected $dbName     = 'db_template';

    # --------------------------------- 查询类接口 START------------------------------------
    /**
     * 获取模板信息
     * @param int  $template_id 模板ID
     * @author MSQ 2021-8-2
    **/
    public function getDetails($template_id = 0,$field = '*')
    {
        $where = [
            'status' => 1,
            'is_use' => 1,
            'id'     => $template_id,
        ];
        if ($field && $field != '*' && count(explode(',', $field)) == 1) {
            // 只取一个字段
            $info = $this->where($where)->value($field);
        }else{
            $info = db($this->dbName)->field($field)->where($where)->find();
        }
        return $info;
    }
    /**
     * 获取数据库使用中模板
     * @param int  $database_id 数据库id
     * @author MSQ 2021-8-2
    **/
    public function getUseingTemplateByDid($database_id = 0,$field = '*')
    {
        $where = [
            'status' => 1,
            'is_use' => 1
        ];
        if (is_array($database_id)) {
            $where['database_id'] = ['IN',$database_id];
        }else{
            $where['database_id'] = $database_id;
        }
        if ($field && $field != '*' && count(explode(',', $field)) == 1) {
            # 只取一个字段
            if (is_array($database_id)) {
                # 有多个数据库取合集
                $info = $this->where($where)->column('id',$field);
            }else{
                $info = $this->where($where)->value($field);
            }
        }else{
            if (is_array($database_id)) {
                $info = db($this->dbName)->field($field)->where($where)->select();
            }else{
                $info = db($this->dbName)->field($field)->where($where)->find();
            }
        }
        return $info;
    }
    /**
     * 获取系统模板
     * @param int  $database_id 数据库id
     * @author MSQ 2021-8-2
    **/
    public function getSysTemplateList($field = '*')
    {
        $where = [
            'status' => 1,
            'is_use' => 1,
            'type'   => 0,
        ];
        $list = db($this->dbName)->field($field)->where($where)->select();
        return $list;
    }
    /**
     * 获取系统基础模板
     * 用于自定义模板及编辑变量右侧边栏渲染
     * @author MSQ 2021-8-11
    **/
    public function getSysBasicTemplateId()
    {
        $where = [
            'status' => 1,
            'is_use' => 1,
            'type'   => 3,
        ];
        $list = db($this->dbName)->where($where)->select();
        return $list;
    }
    /**
     * 获取可引用模板列表
     * @param int  $database_id 数据库id
     * @author MSQ 2021-8-5
    **/
    public function getQuoteTemplateList($parent_id = 0,$usercare_id = 0)
    {
        $templateList  = [];
        $templateField = 'id as template_id,template_name,type,database_id,origin_template_id,introduction,picture_path';

        if (!$parent_id) {
            # 总库 查询系统模板
            $templateList = $this->getSysTemplateList($templateField);
        }else{
            # 子库 查询对应总库及加入该总库的所有子库对应模板
            # 查询医务加入的的总库及其子库信息
            $databaseInfo = model('DbDatabase')->getJoinDbListByParId($usercare_id,$parent_id);            
            if (!$databaseInfo) return [];
            # 查询总库模板
            $masterDbTemplate = $this->getUseingTemplateByDid($parent_id,$templateField);            
            if ($masterDbTemplate) $templateList[] = $masterDbTemplate;
            # 查询子库模板
            foreach ($databaseInfo['childDbInfo'] as $key => $value) {

                $childDbTemplate = $this->getUseingTemplateByDid($value['id'],$templateField);

                if ($childDbTemplate) $templateList[] = $childDbTemplate;
            }
        }
        # 病例数
        foreach ($templateList as $key => $value) {
            $questionCount = model('DbTemplateRelationQuestion')->getTemplateQuestionCount($value['template_id']);
            $templateList[$key]['question_count'] = $questionCount;
        }
        return $templateList;
    }
    /**
     * 获取子库模板
     * @param int  $relevant_id  相关ID 数据库id/模板id
     *             $type         relevant_id类型 1数据库 2模板
     *             $isReturnSelf 是否返回自己
     * @author MSQ 2021-8-5
    **/
    public function getChildDbOrTemplate($relevant_id = 0,$type = 1,$isReturnSelf = 1)
    {
        $database_id = $relevant_id;
        $column = 't.id as tid,d.id as did';
        $parInfo = [];
        if ($type == 2) {
            # 模板 
            $templateInfo = $this->getDetails($relevant_id);
            $database_id = $templateInfo['database_id'];
            # 数据库=>模板
            $column  = 'd.id as did,t.id as tid';
            if ($isReturnSelf) $parInfo = [$database_id => $relevant_id];
        }else{
            if ($isReturnSelf) {
                $databaseInfo = model('db_database')->getDetails($relevant_id);
                # 数据库 模板=>数据库
                $parInfo = [$databaseInfo['template_id'] => $relevant_id];
            }
        }
        if (!$database_id) return false;

        $where = [
            'd.parent_id' => $database_id,
            'd.status'    => 1,
        ];
        $list = db('db_database d')
            ->join('db_template t','t.database_id=d.id AND t.status=1 AND t.is_use=1','LEFT')
            ->where($where)->column($column);
        $returnList = $parInfo+$list;// 返回自身

        return $returnList;
    }
    # ---------------------------------- 查询类接口 END-------------------------------------
    # --------------------------------- 验证类接口 START -----------------------------------
    /**
     * 验证设置模板数据
     * @param int  $template_id 模板ID
     * @author MSQ 2021-8-2
    **/
    public function checkSetTemplate($database_id = 0,$template_id = 0,$data = [],$delArr = [],$quote_template_id = 0)
    {
        if (!$data && !$delArr) return ['code' => 1,'msg' => '无操作'];

        # 数据库和模板id要么都没有要么都要有
        if (($database_id && !$template_id) || ($template_id && !$database_id)) return ['code' => 0,'msg' => '参数错误'];

        if ($database_id) {
            # 已有数据库 编辑
            $databaseInfo = model('DbDatabase')->getDetails($database_id);
            if (!$databaseInfo) return ['code' => 0,'msg' => '数据库不存在'];
            if ($databaseInfo['parent_id']) return ['code' => 0,'msg' => '子库无法操作'];
        }
        
        # 验证基础信息完整性 START ========================================
        if ($template_id) {
            # 模板存在 即编辑变量 验证模板原本的基础信息和住院号是否引用完整
            # 正常情况是引用完整的 因为在创建模板时验证过完整性且后续不可编辑/删除/改模块
            # 追求性能此处可不做验证
            $basicQuestionIds = model('DbQuestion')->getBasicInfo('id');
            $hasBasic = model('DbTemplateRelationQuestion')->checkExistRelationQuestion($template_id,$basicQuestionIds,'question_id');
            $lackQuestion = array_diff($basicQuestionIds,array_filter($hasBasic));
            if ($lackQuestion) return ['code' => 0,'msg' => '基础信息引用不完整'];
            $isBasic = true;
        }else{
            # 没有模板id 创建数据库时自定义模板 
            # 循环到基本信息模块时验证基本信息是否完整
            # 若循环结束isBasic还是false即引用不完整
            # 也可先循环$data验证完基础信息再循环$data验证其他模块
            $isBasic = false;
        }
        # 验证基础信息完整性 END ========================================
        
        # data没有内容初始化为空数组 因前端空数组会被浏览器过滤掉只能传空字符串
        if (!@$data) $data = [];

        # 验证目录名
        $allFirstDirName = array_column($data,'item_name');
        # 过滤无效名称 是否有名称为空
        $validFirstDirName = array_filter($allFirstDirName);
        if (count($allFirstDirName) != count($validFirstDirName)) return ['code' => 0,'msg' => '存在空的一级目录名称'];
        # 去重 不允许同名
        $uniqueFirstDirName = array_unique($allFirstDirName);
        if (count($allFirstDirName) != count($uniqueFirstDirName)) return ['code' => 0,'msg' => '存在重复的一级目录名称'];
        $itemModel = model('DbItem');
        $relationItemModel = model('DbTemplateRelationItem');

        # delArr预组装 补齐item_arr和question_arr
        $delArrNew = $delArr;
        if (!is_array($delArrNew)) {
            $delArrNew = ['item_arr' => [],'question_arr' => []];
        }else{
            if (!$delArrNew['item_arr']) $delArrNew['item_arr'] = [];
            if (!$delArrNew['question_arr']) $delArrNew['question_arr'] = [];
        }
        
        # 验证数据库同名忽略的item_id 即本次修改/删除的所有item
        # 是为解决将A改为为A1 又将B改为A 不过滤会检索到之前的A认为同名
        # 追加上删除item
        # 是为解决删除A 又将B改为A 不过滤会检索到之前的A认为同名
        # TODO：此处是过滤所有删除的item 应过滤当前父级下删除的item即可
        # 即要验证的是本次未改变的，前端没传过来的item 避免修改/删除后仍参与验证
        $ignoreIds = array_unique(array_filter(array_merge(array_column($data,'item_id'),$delArrNew['item_arr'])));

        foreach ($data as $firstDirK => $firstDirV) {
            $item_name = $firstDirV['item_name'];
            if ($template_id) {
                # 一级目录名称是否已存在
                $hasFirstDirName = $relationItemModel->checkItemExistByItemName($template_id,$item_name,0,$ignoreIds);
                if ($hasFirstDirName) return ['code' => 0,'msg' => $item_name.'-已存在'];
            }
            # 有item_id 验证编辑
            if ($firstDirV['item_id']) {
                if ($firstDirV['relation_id']) {
                    # 存在关联 itemInfo读取关联信息
                    $itemInfo = $relationItemModel->getDetails($firstDirV['item_id'],$template_id);
                }elseif ($quote_template_id) {
                    # 暂无关联 itemInfo读取关联模板对应信息
                    $itemInfo = $relationItemModel->getDetails($firstDirV['item_id'],$quote_template_id);
                }else{
                    # 当前模板没有关联也没有引用模板 itemInfo读取总表信息 一般情况下不会走到这
                    $itemInfo = $itemModel->getDetails($firstDirV['item_id']);
                }
                if (!@$itemInfo) return ['code' => 0,'msg' => $item_name.'-信息不存在'];
                # 系统创建不允许修改
                if (!$itemInfo['create_type']) {
                    if ($itemInfo['item_name'] != $item_name) return ['code' => 0,'msg' => $item_name.'-系统目录不允许修改名称'];
                    if ($itemInfo['parent_id']) return ['code' => 0,'msg' => $item_name.'-系统目录不允许修改上级'];
                }
            }
            if ($firstDirV['dir_data']) {
                # 验证目录名
                $allSecondDirName = array_column($firstDirV['dir_data'],'item_name');
                # 过滤无效名称 是否有名称为空 
                $validSecondDirName = array_filter($allSecondDirName);
                if (count($allSecondDirName) != count($validSecondDirName)) return ['code' => 0,'msg' => $item_name.'-存在空的二级目录名称'];
                # 去重 不允许同名
                $uniqueSecondDirName = array_unique($allSecondDirName);
                if (count($allSecondDirName) != count($uniqueSecondDirName)) return ['code' => 0,'msg' => $item_name.'-存在重复的二级目录名称'];

                # 验证数据库同名忽略的item_id 前端传过来的item_id+删除的item_id
                $ignoreIds2 = array_unique(array_filter(array_merge(array_column($firstDirV['dir_data'],'item_id'),$delArrNew['item_arr'])));

                foreach ($firstDirV['dir_data'] as $secondDirK => $secondDirV) {
                    $item_name = $secondDirV['item_name'];
                    if ($template_id && $firstDirV['item_id']) {
                        # 二级目录名称是否已存在
                        $hasSecondDirName = $relationItemModel->checkItemExistByItemName($template_id,$item_name,$firstDirV['item_id'],$ignoreIds2);
                        if ($hasSecondDirName) return ['code' => 0,'msg' => $item_name.'-已存在'];
                    }
                    # 有item_id 验证编辑
                    if ($secondDirV['item_id']) {
                        if ($secondDirV['relation_id']) {
                            # 存在关联 itemInfo读取关联信息
                            $itemInfo = $relationItemModel->getDetails($secondDirV['item_id'],$template_id);
                        }elseif ($quote_template_id) {
                            # 暂无关联 itemInfo读取关联模板对应信息
                            $itemInfo = $relationItemModel->getDetails($secondDirV['item_id'],$quote_template_id);
                        }else{
                            # 当前模板没有关联也没有引用模板 itemInfo读取总表信息 一般情况下不会走到这
                            $itemInfo = $itemModel->getDetails($secondDirV['item_id']);
                        }
                        if (!@$itemInfo) return ['code' => 0,'msg' => $item_name.'-信息不存在'];
                        # 系统创建不允许修改
                        if (!$itemInfo['create_type']) {
                            if ($itemInfo['item_name'] != $item_name) return ['code' => 0,'msg' => $item_name.'-系统目录不允许修改名称'];
                            if ($itemInfo['parent_id'] != $firstDirV['item_id']) return ['code' => 0,'msg' => $item_name.'-系统目录不允许修改上级'];
                        }
                    }
                    $checkRes = $this->checkSetItemAndQuestion($database_id,$template_id,$secondDirV,$quote_template_id,$isBasic,$delArrNew);
                    if ($checkRes['code'] != 1) return $checkRes;
                }
            }else{
                $checkRes = $this->checkSetItemAndQuestion($database_id,$template_id,$firstDirV,$quote_template_id,$isBasic,$delArrNew);
                if ($checkRes['code'] != 1) return $checkRes;
            }
        }
        if (!$isBasic) return ['code' => 0,'msg' => '基础信息引用不完整'];

        # 验证删除信息
        $checkDel = $this->checkSetTemplateInDel($template_id,$delArr,$database_id);
        if ($checkDel['code'] != 1) return $checkDel;

        return ['code' => 1,'msg' => '验证成功'];
    }
    /**
     * 验证设置模板-模块及变量数据准确性
     * @param int  $template_id 模板ID
     * @param int  $data 设置的数据
     * @author MSQ 2021-8-2
    **/
    public function checkSetItemAndQuestion($database_id = 0,$template_id = 0,$data = [],$quote_template_id = 0,&$isBasic = false,$delArr = [])
    {
        if (!$data) return true;
        if (!@$data['item_data']) $data['item_data'] = [];

        $itemModel     = model('DbItem');
        $questionModel = model('DbQuestion');
        $relationItemModel     = model('DbTemplateRelationItem');
        $relationQuestionModel = model('DbTemplateRelationQuestion');

        if (!$isBasic) {
            # 必须存在的基本信息ids
            $basicQuestionIds = $questionModel->getBasicInfo('id');
            # 基本信息模块id
            $basicItemId = $itemModel->getBasicItemInfo('id');
        }
        # 验证一级模块名
        $allFirstItemName = array_column($data['item_data'],'item_name');                
        # 过滤无效名称 是否有名称为空
        $validFirstItemName = array_filter($allFirstItemName);
        if (count($allFirstItemName) != count($validFirstItemName)) return ['code' => 0,'msg' => $data['item_name'].'-存在空的一级模块名称'];

        # 去重 不允许同名
        $uniqueFirstItemName = array_unique($allFirstItemName);
        if (count($allFirstItemName) != count($uniqueFirstItemName)) return ['code' => 0,'msg' =>  $data['item_name'].'-存在重复的一级模块名称'];
        # 验证数据库同名忽略的item_id 前端传过来的item_id+删除的item_id
        $ignoreIds1 = array_unique(array_filter(array_merge(array_column($data['item_data'],'item_id'),$delArr['item_arr'])));
        if ($template_id) {
            # 取出所有一级模块对应的二级模块
            $allFirstItemIds = array_filter(array_column($data['item_data'],'item_id'));
            $allChildItem = [];
            if ($allFirstItemIds) {
                $allChildItem = $relationItemModel->getChildItem($allFirstItemIds,$template_id);
                $allChildItem = arrayGroupByKey($allChildItem,'parent_id');
            }
        }

        foreach ($data['item_data'] as $firstItemK => $firstItemV) {
            $item_name = $firstItemV['item_name'];
            if ($template_id && $data['item_id']) {
                # 一级模块名称是否已存在
                $hasFirstItemName = $relationItemModel->checkItemExistByItemName($template_id,$item_name,$data['item_id'],$ignoreIds1);                
                if ($hasFirstItemName) return ['code' => 0,'msg' => $item_name.'-已存在'];
            }
            # 有item_id 验证编辑
            if ($firstItemV['item_id']) {
                if ($firstItemV['relation_id']) {
                    # 存在关联 itemInfo读取关联信息
                    $itemInfo = $relationItemModel->getDetails($firstItemV['item_id'],$template_id);
                }elseif ($quote_template_id) {
                    # 暂无关联 itemInfo读取关联模板对应信息
                    $itemInfo = $relationItemModel->getDetails($firstItemV['item_id'],$quote_template_id);
                }else{
                    # 当前模板没有关联也没有引用模板 itemInfo读取总表信息 一般情况下不会走到这
                    $itemInfo = $itemModel->getDetails($firstItemV['item_id']);
                }
                if (!@$itemInfo) return ['code' => 0,'msg' => $item_name.'-信息不存在'];
                # 系统创建不允许修改
                if (!$itemInfo['create_type']) {
                    if ($itemInfo['item_name'] != $item_name) return ['code' => 0,'msg' => $item_name.'-系统模块不允许修改名称'];
                    if ($itemInfo['parent_id'] != $data['item_id']) return ['code' => 0,'msg' => $item_name.'-系统模块不允许修改上级'];
                }
            }
            if (!@$firstItemV['item_data']) $firstItemV['item_data'] = [];

            # 验证二级模块名
            $allSecondItemName = array_column($firstItemV['item_data'],'item_name');
            # 过滤无效名称 是否有名称为空
            $validSecondItemName = array_filter($allSecondItemName);
            if (count($allSecondItemName) != count($validSecondItemName)) return ['code' => 0,'msg' => $item_name.'-存在空的二级模块名称'];
            # 去重 不允许同名
            $uniqueSecondItemName = array_unique($allSecondItemName);
            if (count($allSecondItemName) != count($uniqueSecondItemName)) return ['code' => 0,'msg' => $item_name.'-存在重复的二级模块名称'];
            # 验证数据库同名忽略的item_id 前端传过来的item_id+删除的item_id
            // $ignoreIds2 = array_unique(array_filter(array_merge(array_column($firstItemV['item_data'],'item_id'),$delArr['item_arr'])));

            # 前端传过来的二级模块ID合集
            $newSecondItemIds = array_column($firstItemV['item_data'],'item_id');
            $isUpWeight = isset($firstItemV['is_up_weight']) ? $firstItemV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
            if ($isUpWeight && $newSecondItemIds) {
                $oldSecondItemIds = @array_column($allChildItem[$firstItemV['item_id']],'id');
                $removeQuestonId  = @array_diff($oldSecondItemIds,$newSecondItemIds);
                # 将移除的(移到其他一级模块+删除)模块加入忽略
                $ignoreIds2 = $newSecondItemIds;
                if ($removeQuestonId) $ignoreIds2 = array_merge($ignoreIds2,$removeQuestonId);
            }

            foreach ($firstItemV['item_data'] as $itemK => $itemV) {
                $item_name = $itemV['item_name'];
                if ($template_id && $firstItemV['item_id'] && !$isUpWeight) {
                    $ignoreIds2 = array_filter(array_unique($ignoreIds2));
                    # 二级模块名称是否已存在
                    $hasItemName = $relationItemModel->checkItemExistByItemName($template_id,$item_name,$firstItemV['item_id'],$ignoreIds2);
                    if ($hasItemName) return ['code' => 0,'msg' => $item_name.'-已存在'];
                }
                # 有item_id 验证编辑
                if ($itemV['item_id']) {
                    if ($itemV['relation_id']) {
                        # 存在关联 itemInfo读取关联信息
                        $itemInfo = $relationItemModel->getDetails($itemV['item_id'],$template_id);
                    }elseif ($quote_template_id) {
                        # 暂无关联 itemInfo读取关联模板对应信息
                        $itemInfo = $relationItemModel->getDetails($itemV['item_id'],$quote_template_id);
                    }else{
                        # 当前模板没有关联也没有引用模板 itemInfo读取总表信息 一般情况下不会走到这
                        $itemInfo = $itemModel->getDetails($itemV['item_id']);
                    }
                    if (!@$itemInfo) return ['code' => 0,'msg' => $item_name.'-信息不存在'];
                    # 系统创建不允许修改
                    if (!$itemInfo['create_type']) {
                        if ($itemInfo['item_name'] != $item_name) return ['code' => 0,'msg' => $item_name.'-系统模块不允许修改名称'];
                        if ($itemInfo['parent_id'] != $firstItemV['item_id']) return ['code' => 0,'msg' => $item_name.'-系统模块不允许修改上级'];
                    }
                }
                if (!@$itemV['question_data']) $itemV['question_data'] = [];

                # 验证一级变量名称
                $allQuestionName = array_column($itemV['question_data'],'question_name');      
                # 过滤无效名称 是否有名称为空
                $validQuestionName = array_filter($allQuestionName);
                if (count($allQuestionName) != count($validQuestionName)) return ['code' => 0,'msg' => $item_name.'-存在空的一级变量名称'];
                # 按变量名分组 允许同名不同类型
                $questionNameGroup = arrayGroupByKey($itemV['question_data'],'question_name');
                # 验证数据库同名忽略的question_id 即本次修改/删除的所有question
                # 是为解决将变量A改为为A1 又将变量B改为A 不过滤会检索到之前的A为同名
                # 追加上删除变量
                # 是为解决删除变量A 又将变量B改为A 不过滤会检索到之前的A为同名
                # TODO：此处是过滤所有删除的变量 应过滤当前模块下删除的变量即可
                # 即要验证的是本次未改变的，前端没传过来的变量 避免修改/删除后仍参与验证
                $ignoreIds3 = array_unique(array_filter(array_merge(array_column($itemV['question_data'],'question_id'),$delArr['question_arr'])));
                // $isUpWeight = isset($itemV['is_up_weight']) ? $itemV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序

                # 查出各变量组下对应变量 用于检索变量组下同名变量
                if ($template_id) {
                    # 按变量类型分组
                    $questionTypeGroup = arrayGroupByKey($itemV['question_data'],'question_type');
                    # 所有变量组ID
                    $questionGroupIds = @array_filter(array_column($questionTypeGroup[0],'question_id'));
                    # 所有变量组对应子变量
                    $allChildQuestion = $relationQuestionModel->getChildQuestionByPid($questionGroupIds,$template_id);
                    # 按变量组id分组
                    $allChildQuestion = arrayGroupByKey($allChildQuestion,'parent_id');
                }
                foreach ($itemV['question_data'] as $questionK => $questionV) {
                    $question_name = $questionV['question_name'];

                    # 验证是否存在同名同类型-前端传过来数据对比
                    $questionNameArr = $questionNameGroup[$question_name];
                    # 同名变量超过1个
                    if (count($questionNameArr) > 1) {
                        # 相同变量名的变量类型合集
                        $questionNameType = array_column($questionNameArr,'question_type');
                        # 相同变量名的数量>去重变量类型 存在同一变量名相同类型
                        if (count($questionNameArr) > count(array_unique($questionNameType))) {
                            return ['code' => 0,'msg' => $item_name.'-'.$question_name.'-名称存在重复'];
                        }
                    }

                    # 验证变量类型
                    if (!@in_array($questionV['question_type'],[0,1,2,3,4,5,6,7])) return ['code' => 0,'msg' => $question_name.'-变量类型错误'];

                    if ($template_id && $itemV['item_id']) {
                        # 验证是否存在同名同类型-与数据库已存在的对比
                        $hasQuestionName = $relationQuestionModel->checkQuestionExistByQuestionName($template_id,$question_name,$itemV['item_id'],0,$ignoreIds3,$questionV['question_type']);
                        if ($hasQuestionName) return ['code' => 0,'msg' => $item_name.'-'.$question_name.'-已存在'];
                    }

                    # 有question_id 验证编辑
                    if ($questionV['question_id']) {
                        if ($questionV['relation_id']) {
                            # 存在关联 questionInfo读取关联信息
                            $questionInfo = $relationQuestionModel->getDetails($questionV['question_id'],$template_id);
                        }elseif ($quote_template_id) {
                            # 暂无关联 questionInfo读取关联模板对应信息
                            $questionInfo = $relationQuestionModel->getDetails($questionV['question_id'],$quote_template_id);
                        }else{
                            # 当前模板没有关联也没有引用模板 questionInfo读取总表信息 一般情况下不会走到这 
                            $questionInfo = $questionModel->getDetails($questionV['question_id']);
                        }
                        if (!@$questionInfo) return ['code' => 0,'msg' => $question_name.'-信息不存在'];
                        # 编辑变量验证数据合法性 系统变量及有回答的不允许修改
                        $questionV['item_id'] = $itemV['item_id'];
                        $questionV['parent_id'] = 0;
                        $editRes = $questionModel->checkEditQuestionLegitimacy($database_id,$template_id,$questionInfo,$questionV);
                        if ($editRes['code'] != 1) return ['code' => $editRes['code'],'msg' => $question_name.'-'.$editRes['msg']];
                    }
                    # 验证选项
                    if (in_array($questionV['question_type'],[1,2,3])) {
                        if (!$questionV['option_list']) return ['code' => 0,'msg' => $question_name.'-选项不能为空'];
                        $allOptionName = array_column($questionV['option_list'],'option_name');
                        # 过滤无效名称 是否有名称为空 
                        # array_filter会将0过滤 有些选项名称就是0 将采用前端拦截 后端不做处理
                        /*$validOptionName = array_filter($allOptionName);
                        if (count($allOptionName) != count($validOptionName)) return ['code' => 0,'msg' => $question_name.'-存在空的选项名称'];*/

                        # 去重 不允许同名
                        $uniqueOptionName = array_unique($allOptionName);
                        if (count($allOptionName) != count($uniqueOptionName)) return ['code' => 0,'msg' => $question_name.'-存在重复的选项名称'];   
                    }
                    if (!@$questionV['child_question']) $questionV['child_question'] = [];

                    # 验证二级变量名称
                    $allQuestionName2 = array_column($questionV['child_question'],'question_name');
                    # 过滤无效名称 是否有名称为空
                    $validQuestionName2 = array_filter($allQuestionName2);                    
                    if (count($allQuestionName2) != count($validQuestionName2)) return ['code' => 0,'msg' => $question_name.'存在空的变量名称'];
                    # 按变量名分组 允许同名不同类型
                    $questionNameGroup2 = arrayGroupByKey($questionV['child_question'],'question_name');
                    # 前端传过来的变量ID合集
                    $newChildQuestionIds = array_column($questionV['child_question'],'question_id');
                    
                    # 是否更新排序 即是否将完整的变量组列表传过来 
                    # 目前是固定完整的 后续会按需传值 可能只传编辑的
                    $isUpWeight2 = isset($questionV['is_up_weight']) ? $questionV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
                    if ($isUpWeight2 && $newChildQuestionIds) {
                        # 原变量组下的子变量id
                        $oldChildQuestionIds = @array_column($allChildQuestion[$questionV['question_id']],'id');
                        # 移出的变量id 取旧的子变量与新的子变量差集 即原本有的本次删除/移走的加入忽略不参与同名检测
                        # 是为避免A组有变量X B组有变量X 将两X互换 会找到原同组内的X报X已存在
                        # 即要忽略的是前端传过来的列表&删除&移走的 参与比对的是编辑情况下从未改动的数据即前端没传过来的变量且未删除未移走的
                        $removeQuestonId = @array_diff($oldChildQuestionIds,$newChildQuestionIds);
                        # 将移走的变量加入忽略
                        # 验证数据库同名忽略的question_id 前端传过来的question_id +删除的question_id 
                        # 删除的在取移出的变量id可同步取出，且只取该变量组下的，比追加全部的删除变量id更加精准
                        $ignoreIds5 = $newChildQuestionIds;
                        if ($removeQuestonId) $ignoreIds5 = array_merge($ignoreIds5,$removeQuestonId);
                    }
                        
                    foreach ($questionV['child_question'] as $questionK2 => $questionV2) {
                        $question_name = $questionV2['question_name'];
                        
                        # 验证是否存在同名同类型-前端传过来数据对比
                        $questionNameArr2 = $questionNameGroup2[$question_name];
                        # 同名变量超过1个
                        if (count($questionNameArr2) > 1) {
                            # 相同变量名的变量类型合集
                            $questionNameType2 = array_column($questionNameArr2,'question_type');
                            # 相同变量名的数量>去重变量类型 存在同一变量名相同类型
                            if (count($questionNameArr2) > count(array_unique($questionNameType2))) {
                                return ['code' => 0,'msg' => $item_name.'-'.$questionV['question_name'].'-'.$question_name.'-名称存在重复'];
                            }
                        }

                        # 验证变量类型
                        if (!@in_array($questionV2['question_type'],[1,2,3,4,5,6,7])) return ['code' => 0,'msg' => $question_name.'-变量类型错误'];
                        # 存在模板&模块&变量组id&非排序(排序的话所有变量都传过来在前面已经验证过了)
                        if ($template_id && $itemV['item_id'] && $questionV['question_id'] && !$isUpWeight2) {
                            $ignoreIds5 = array_filter(array_unique($ignoreIds5));
                            # 验证是否存在同名同类型-与数据库已存在的对比
                            $hasQuestionName2 = $relationQuestionModel->checkQuestionExistByQuestionName($template_id,$question_name,$itemV['item_id'],$questionV['question_id'],$ignoreIds5,$questionV2['question_type']);
                            if ($hasQuestionName2) return ['code' => 0,'msg' => $question_name.'-已存在'];
                        }
                        # 有question_id 验证编辑
                        if ($questionV2['question_id']) {
                            if ($questionV2['relation_id']) {
                                # 存在关联 questionInfo读取关联信息
                                $questionInfo = $relationQuestionModel->getDetails($questionV2['question_id'],$template_id);
                            }elseif ($quote_template_id) {
                                # 暂无关联 questionInfo读取关联模板对应信息
                                $questionInfo = $relationQuestionModel->getDetails($questionV2['question_id'],$quote_template_id);
                            }else{
                                # 当前模板没有关联也没有引用模板 questionInfo读取总表信息 一般情况下不会走到这
                                $questionInfo = $questionModel->getDetails($questionV2['question_id']);
                            }
                            if (!$questionInfo) return ['code' => 0,'msg' => $question_name.'-信息不存在'];
                            # 编辑变量验证数据合法性 系统变量及有回答的不允许修改
                            $questionV2['item_id']   = $itemV['item_id'];
                            $questionV2['parent_id'] = $questionV['question_id'];
                            $editRes = $questionModel->checkEditQuestionLegitimacy($database_id,$template_id,$questionInfo,$questionV2);
                            if ($editRes['code'] != 1) return ['code' => $editRes['code'],'msg' => $question_name.'-'.$editRes['msg']];
                        }
                        # 验证选项
                        if (in_array($questionV2['question_type'],[1,2,3])) {
                            if (!$questionV2['option_list']) return ['code' => 0,'msg' => $question_name.'-选项不能为空'];

                            $allOptionNameArr2 = array_column($questionV2['option_list'],'option_name');

                            # 过滤无效名称 是否有名称为空
                            # array_filter会将0过滤 将采用前端拦截 后端不做处理
                            /*$validOptionName2 = array_filter($allOptionNameArr2);
                            if (count($allOptionNameArr2) != count($validOptionName2)) return ['code' => 0,'msg' => $question_name.'-存在空的选项名称'];*/
                            # 去重 不允许同名
                            $uniqueOptionNameArr2 = array_unique($allOptionNameArr2);
                            if (count($allOptionNameArr2) != count($uniqueOptionNameArr2)) return ['code' => 0,'msg' => $question_name.'-存在重复的选项名称'];   
                        }
                    }
                }
                if (!$isBasic && !$template_id && $basicItemId == $itemV['item_id']) {
                    # 验证基础信息否完整
                    $questionIdArr = array_column($itemV['question_data'],'question_id');
                    $lackQuestion  = array_diff($basicQuestionIds,array_filter($questionIdArr));
                    if ($lackQuestion) return ['code' => 0,'msg' => $item_name.'-基础信息引用不完整'];
                    $isBasic = true;
                }                
            }
        }
        return ['code' => 1,'msg' => '验证成功'];
    }
    /**
     * 设置模板-验证删除数据
     * @param int  $template_id 模板ID
     * @param int  $delArr 删除数据 item_arr删除模块 question_arr删除变量
     * @param int  $database_id 数据库id
     * @author MSQ 2021-8-17
    **/
    public function checkSetTemplateInDel($template_id = 0,$delArr = [],$database_id = 0)
    {
        if (!$delArr) return ['code' => 1,'msg' => '验证成功'];
        if (!$template_id || !$database_id) return ['code' => 0,'msg' => '参数错误'];

        $relationItemModel = model('DbTemplateRelationItem');
        $relationQuestionModel = model('DbTemplateRelationQuestion');

        if (!@$delArr['item_arr']) $delArr['item_arr'] = [];
        if (!@$delArr['question_arr']) $delArr['question_arr'] = [];
        if($delArr['item_arr']){
            $item_ids  = $delArr['item_arr'];
            # 所有删除item的信息
            $itemInfos = $relationItemModel->getDetails($item_ids,$template_id);
            $itemInfos = array_column($itemInfos,NULL,'item_id');
            # 所有删除item的子item
            $childItems = $relationItemModel->getChildItem($item_ids,$template_id);
            $childItems = arrayGroupByKey($childItems,'parent_id');
            # 所有删除模块的变量
            $itemQuestions = $relationQuestionModel->getQuestionByItemId($item_ids,$template_id);
            $itemQuestions = arrayGroupByKey($itemQuestions,'item_id');

            foreach ($item_ids as $itemK => $itemV) {
                # 是否是系统创建
                $itemInfo = @$itemInfos[$itemV];
                if (!$itemInfo) return ['code' => 0,'msg' => '目录/模块不存在或已删除'];
                if (!$itemInfo['create_type']) return ['code' => 0,'msg' => '系统创建不允许删除'];
                
                # 下级item_id
                $childItem = @array_column($childItems[$itemV],'item_id');

                # 存在下级 下级是否在delArr内
                $lackItem = @array_diff($childItem,$item_ids);
                if ($lackItem) return ['code' => 0,'msg' => $itemInfo['item_name'].'-存在下级不允许删除'];

                if ($itemInfo['type'] == 2 && $itemInfo['classify_rank'] == 2) {
                    # 二级模块是否存在未删除的变量
                    $questionId   = @array_column($itemQuestions[$itemV],'question_id'); 

                    $lackQuestion = @array_diff($questionId,$delArr['question_arr']);
                    if ($lackQuestion) return ['code' => 0,'msg' => $itemInfo['item_name'].'-存在变量不允许删除'];
                }
            }
        }
        if($delArr['question_arr']){
            $question_ids  = $delArr['question_arr'];

            # 所有删除变量的信息
            $questionInfos = $relationQuestionModel->getQuestionByQids($template_id,$question_ids,1);
            $questionInfos = array_column($questionInfos,NULL,'question_id');
            # 所有删除变量的子变量
            $childQuestions = $relationQuestionModel->getChildQuestionByPid($question_ids,$template_id);
            $childQuestions = arrayGroupByKey($childQuestions,'parent_id');
            # 所有删除变量的回答
            $hasDataQids = model('DbData')->getDataByQuestionId($database_id,$question_ids,'question_id');
            $hasDataQids = array_flip(array_unique($hasDataQids));

            foreach ($question_ids as $questionK => $questionV) {
                $questionInfo = $questionInfos[$questionV];
                if (!$questionInfo) return ['code' => 0,'msg' => '变量不存在或已删除'];

                if (!$questionInfo['create_type']) return ['code' => 0,'msg' => '系统创建不允许删除'];
                # 变量组 检索是否存在未删除下级变量
                if (!$questionInfo['question_type']) {
                    $childQuestion = @array_column($childQuestions[$questionV],'question_id');
                    $lackQuestion  = @array_diff($childQuestion,$question_ids);
                    if ($lackQuestion) return ['code' => 0,'msg' => $questionInfo['question_name'].'-存在二级变量不允许删除'];
                }else{
                    # 一级变量或二级变量 检索是否存在回答
                    if (isset($hasDataQids[$questionV])) return ['code' => 0,'msg' => $questionInfo['question_name'].'-存在回答不允许删除'];
                }
            }
        }
        return ['code' => 1,'msg' => '验证成功'];
    }
    # ---------------------------------- 验证类接口 END -------------------------------------

    # ------------------------------- 数据处理类接口 START ----------------------------------
    /**
     * 创建模板数据
     * @param int  $template_id 模板ID
     * @author MSQ 2021-8-2
    **/
    public function addData($database_id = 0,$origin_template_id = 0)
    {
        $template_name = model('DbDatabase')->getDetails($database_id,'database_name');
        if (!$template_name) return false;

        $data = [
            'template_name'      => $template_name,
            'database_id'        => $database_id,
            'type'               => 1,
            'is_use'             => 1,
            'origin_template_id' => $origin_template_id
        ];
        $this->setAttr('id',null)->isUpdate(false)->save($data);
        if (!isset($this->id)) return false;
        return $this->id;
    }
    /**
     * 创建模板
     * @param int  $database_id 数据库id
     * @param int  $origin_template_id 引用模板 0表示仅引用基础模板的基础信息
     * @author MSQ 2021-8-2
    **/
    public function createTemplate($database_id = 0,$origin_template_id = 0,$usercare_id = 0)
    {
        if (!$database_id) return false;
        # 生成模板id
        $template_id = $this->addData($database_id,$origin_template_id);
        if (!$template_id) return false;
        # 数据库信息
        $databaseInfo = model('DbDatabase')->getDetails($database_id);
        if (!$databaseInfo) return false;

        set_time_limit(0);
        ini_set('memory_limit', '-1');
        $relationItemModel = model('DbTemplateRelationItem');
        if (!$databaseInfo['parent_id'] || !$origin_template_id) {
            # 基础信息相关目录&模块
            $basicItem = model('DbItem')->getBasicDirChildItem();
            $basicItemIds = array_column($basicItem,'id');
        }
        
        if ($databaseInfo['parent_id'] || !$origin_template_id) {
            # 子库(同步引用模板全部数据)或不引用模板的总库(同步基础模板的基础信息)
            $where = []; # 子库不自定义where
            if (!$origin_template_id) {
                # 没有引用模板 取基础模板id 新增的是总库但不引用模板
                $origin_template_id = @$this->getSysBasicTemplateId()[0]['id'];
                $where = [
                    'template_id' => $origin_template_id, // 同步基础模板
                    'item_id'     => ['IN',$basicItemIds],// 仅同步基础信息
                ];
            }
            # 子库 只需向关联表添加数据
            # 同步item关联
            $itemRelationRes = $relationItemModel->addTemplateRelationItemByTemplateId($origin_template_id,$template_id,$database_id,$where);
            if (!$itemRelationRes) return false;

            # 新增变量关联
            $questionRelationRes = model('DbTemplateRelationQuestion')->addTemplateRelationQuestionByTemplateId($origin_template_id,$template_id,$database_id,$where);
            if (!$questionRelationRes) return false;

            if ($where) {
                # 有where的表示新增的是总库但不引用模板
                unset($where['item_id']);// 删掉item_id限制
                # 查出基础信息相关模块下变量
                $allBasicQuestionIds = model('DbTemplateRelationQuestion')->getQuestionByItemId($basicItemIds,$template_id,'q.id');
                # 仅同步基础信息相关变量
                $where['question_id'] = ['IN',$allBasicQuestionIds];
            }
            
            # 新增选项关联
            $optionRelationRes = model('DbTemplateRelationQuestionOption')->addTemplateRelationOptionByTemplateId($origin_template_id,$template_id,$database_id,$where);
            if (!$optionRelationRes) return false;

        }else{
            # 总库 引用系统变量 总表和关联表都需添加数据
            # 基础信息相关目录 总表不新增数据 仅引用
            $relationItemData = [];
            # 递归引用目录&模块 从一级目录->二级模块 方法内调同步变量&选项
            $res = $relationItemModel->recursionSyncItemForQuoteTemplate($origin_template_id,$template_id,$database_id,$usercare_id,0,0,$basicItemIds,$relationItemData);
            if (!$res) return false;
            
            # 批量新增关联目录&模块
            $relationItemData = array_chunk($relationItemData, 1000);
            foreach ($relationItemData as $key => $value) {
                $relationItemModel->setAttr('id',null)->isUpdate(false)->saveAll($value);
            }
        }        
        return $template_id;
    }
    /**
     * 清除缓存中模板下变量列表
     * template_id 模板id 可单个可数组
     * isClearRelation 是否清除关联模板数据
     * MSQ 2021-8-30
     */
    public function clearTemplateQueationRedis($template_id = 0,$isClearRelation = 0){
        if (!$template_id) return true;

        # 清除关联模板数据 及其下子库模板
        if ($isClearRelation && !is_array($template_id)) {
            $template_id = $this->getChildDbOrTemplate($template_id,2,1);
            if (!$template_id) return false;
        }
        if (is_array($template_id)) {
            $template_id = array_unique($template_id);
            # 编辑/删除变量时需要同步操作关联了对应变量的模块
            foreach ($template_id as $key => $value) {
                $cacheKey = 'question_list_'.$value;
                Cache::clear($cacheKey);
            }
        }else{
            $cacheKey = 'question_list_'.$template_id;
            Cache::clear($cacheKey);
        }
        return true;
    }
    /**
     * 设置模板
     * 该方法包含新增/编辑/删除/排序-目录
     * template_id 模板id 可单个可数组
     * database_id 数据库id
     * data 设置参数
     * MSQ 2021-8-11
     */
    public function setTemplate($template_id = 0,$database_id = 0,$data = [],$usercare_id = 0){
        if (!$database_id || !$template_id) return ['code' => 0,'msg' => ''];
        $selectDirId = 0;// 选择的目录id
        if (!$data) return ['code' => 1,'msg' => '','selectDirId' => $selectDirId];

        $itemModel         = model('DbItem');
        $relationItemModel = model('DbTemplateRelationItem');
        $firstDirCount     = count($data);
        foreach ($data as $firstDirK => $firstDirV) {
            $firstDirId = $firstDirV['item_id'];
            $firstDirV['template_id']   = $template_id;
            $firstDirV['database_id']   = $database_id;
            $firstDirV['type']          = 1;
            $firstDirV['classify_rank'] = 1;
            $firstDirV['parent_id']     = 0;
            $firstDirV['usercare_id']   = $usercare_id;
            # 只有一个一级目录默认为编辑-不更新权重
            # 其他是否更新权重由上一级is_up_weight决定 而一级目录已经是顶级了并没有上一级
            if (count($data) > 1) $firstDirV['weight'] = $firstDirCount;
            # 新增一级目录-主表
            if (!$firstDirId) {
                $firstDirId = $itemModel->createItem($firstDirV);
                if (@$firstDirV['is_select'] && $firstDirId) $selectDirId = $firstDirId;
            }
            if (!$firstDirId) return ['code' => 0,'msg' => '2'];
            $firstDirV['item_id'] = $firstDirId;
            if (!$firstDirV['relation_id']) {
                # 新增一级目录关联
                $relation_id = $relationItemModel->createRelationItem($firstDirV);
                if (!$relation_id) return ['code' => 0,'msg' => '3'];
            } else {
                # 编辑一级目录
                $itemInfo = $relationItemModel->getDetails($firstDirId,$template_id);
                if (!$itemInfo) return ['code' => 0,'msg' => '5'];
                # 修改一级目录关联数据 含更新目录主表
                $saveItem = $relationItemModel->setItem($firstDirV);
                if (!$saveItem) return ['code' => 0,'msg' => '6'];        
            }
            $firstDirCount--;
            if ($firstDirV['dir_data']) {
                $secondDirCount  = count($firstDirV['dir_data']);
                $isUpWeight = isset($firstDirV['is_up_weight']) ? $firstDirV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
                foreach ($firstDirV['dir_data'] as $secondDirK => $secondDirV) {
                    $secondDirId = $secondDirV['item_id'];
                    $secondDirV['template_id']   = $template_id;
                    $secondDirV['database_id']   = $database_id;
                    $secondDirV['type']          = 1;
                    $secondDirV['classify_rank'] = 2;
                    $secondDirV['parent_id']     = $firstDirId;
                    $secondDirV['usercare_id']   = $usercare_id;
                    if ($isUpWeight) $secondDirV['weight'] = $secondDirCount;

                    # 新增二级目录-主表
                    if (!$secondDirId) {
                        $secondDirId = $itemModel->createItem($secondDirV);
                        if (@$secondDirV['is_select'] && $secondDirId) $selectDirId = $secondDirId;
                    }
                    if (!$secondDirId) return ['code' => 0,'msg' => '7'];
                    $secondDirV['item_id'] = $secondDirId;

                    if (!$secondDirV['relation_id']) {
                        # 新增二级目录关联
                        $relation_id = $relationItemModel->createRelationItem($secondDirV);
                        if (!$relation_id) return ['code' => 0,'msg' => '8'];
                    }else{
                        # 修改二级目录关联数据 含更新目录主表
                        $saveItem = $relationItemModel->setItem($secondDirV);
                        if (!$saveItem) return ['code' => 0,'msg' => '10'];
                    }
                    $secondDirCount--;                    
                    # 添加模块及变量
                    $itemAndQuestionRes = $this->setItemAdnQuestion($template_id,$secondDirId,$secondDirV,$usercare_id,$database_id);
                    if ($itemAndQuestionRes !== true) return ['code' => 0,'msg' => $itemAndQuestionRes];
                }
            } else {
                # 无二级目录 添加模块及变量
                $itemAndQuestionRes = $this->setItemAdnQuestion($template_id,$firstDirId,$firstDirV,$usercare_id,$database_id);
                if ($itemAndQuestionRes !== true) return ['code' => 0,'msg' => $itemAndQuestionRes];
            }
        }

        # 清除模板变量列表缓存
        $this->clearTemplateQueationRedis($template_id,1);
        return ['code' => 1,'msg' => '','selectDirId' => $selectDirId];
        return true;
    }
    /**
     * 设置模板-添加模块及变量
     * 该方法包含新增/编辑/删除/排序-模块/变量
     * template_id 模板id
     * dirId       目录ID
     * data        模块及变量数据
     * MSQ 2021-8-11
     */
    public function setItemAdnQuestion($template_id = 0,$dirId = 0,$data = [],$usercare_id = 0,$database_id = 0)
    {
        if (!$data['item_data']) return true;
        if (!$template_id || !$dirId || !$database_id) return false;

        $itemModel     = model('DbItem');
        $questionModel = model('DbQuestion');
        $relationItemModel     = model('DbTemplateRelationItem');
        $relationQuestionModel = model('DbTemplateRelationQuestion');

        $firstItemCount = count($data['item_data']);
        $isUpWeight     = isset($data['is_up_weight']) ? $data['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
        foreach ($data['item_data'] as $firstItemK => $firstItemV) {
            # 处理一级模块
            $firstItemId = $firstItemV['item_id'];
            $firstItemV['template_id']   = $template_id;
            $firstItemV['database_id']   = $database_id;
            $firstItemV['type']          = 2;
            $firstItemV['classify_rank'] = 1;
            $firstItemV['parent_id']     = $dirId;
            $firstItemV['usercare_id']   = $usercare_id;
            if ($isUpWeight) $firstItemV['weight'] = $firstItemCount;

            # 新增一级模块-主表
            if (!$firstItemId) $firstItemId = $itemModel->createItem($firstItemV);              
            if (!$firstItemId) return 13;
            $firstItemV['item_id'] = $firstItemId;

            if (!$firstItemV['relation_id']) {
                # 新增一级模块关联
                $relation_id = $relationItemModel->createRelationItem($firstItemV);
                if (!$relation_id) return 15;
            }else{
                # 修改一级模块关联数据 含更新模块主表
                $saveItem = $relationItemModel->setItem($firstItemV);
                if (!$saveItem) return 17;
            }            
            --$firstItemCount;

            if (!@$firstItemV['item_data']) $firstItemV['item_data'] = [];
            # 处理二级模块
            $itemCount = count($firstItemV['item_data']);
            # 是否更新权重 
            # 避免只编辑部分模块没有将所有模块传过来而导致未编辑的模块权重不变影响整体排序
            # 例如只操作A模块(原weight为10),前端只将A传过来,此次更新会将A的权重改成1而导致A排到最后
            $isUpWeight = isset($firstItemV['is_up_weight']) ? $firstItemV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
            foreach ($firstItemV['item_data'] as $itemK => $itemV) {
                $itemId = $itemV['item_id'];
                $itemV['template_id']   = $template_id;
                $itemV['database_id']   = $database_id;
                $itemV['type']          = 2;
                $itemV['classify_rank'] = 2;
                $itemV['parent_id']     = $firstItemId;  
                $itemV['usercare_id']   = $usercare_id;
                if ($isUpWeight) $itemV['weight'] = $itemCount;

                # 新增二级模块-主表
                if (!$itemId) $itemId = $itemModel->createItem($itemV);
                if (!$itemId) return 18;
                $itemV['item_id'] = $itemId;

                if (!$itemV['relation_id']) {
                    # 新增二级模块关联
                    $relation_id = $relationItemModel->createRelationItem($itemV);      
                    if (!$relation_id) return 19;
                }else{
                    # 修改二级目录关联数据 含更新目录主表
                    $saveItem = $relationItemModel->setItem($itemV);
                    if (!$saveItem) return 21;
                }
                $itemCount--;
                if (!@$itemV['question_data']) $itemV['question_data'] = [];

                # 处理变量组/一级变量
                $firstQuestionCount = count($itemV['question_data']);
                $isUpWeight = isset($itemV['is_up_weight']) ? $itemV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
                foreach ($itemV['question_data'] as $questionK => $questionV) {
                    $firstQuestionId = $questionV['question_id'];  
                    $questionV['template_id'] = $template_id;
                    $questionV['database_id'] = $database_id;
                    $questionV['item_id']     = $itemId;
                    $questionV['usercare_id'] = $usercare_id;
                    $questionV['parent_id']   = 0;
                    if ($isUpWeight) $questionV['weight'] = $firstQuestionCount;
                    # 新增变量组/一级变量 含新增选项
                    if (!$firstQuestionId) $firstQuestionId = $questionModel->createQuestion($questionV);
                    if (!$firstQuestionId) return 22;
                    $questionV['question_id'] = $firstQuestionId;

                    if (!$questionV['relation_id']) {
                        # 新增变量组/一级变量关联 含新增关联选项
                        $relation_id = $relationQuestionModel->createRelationQuestion($questionV);
                        if (!$relation_id) return 23;
                    }else{
                        # 编辑变量
                        $saveQuestion = $relationQuestionModel->saveQuestion($template_id,$firstQuestionId,$questionV,$usercare_id);
                        if (!$saveQuestion) return 25;
                    }
                    $firstQuestionCount--;
                    # 处理二级变量
                    if ($questionV['question_type'] == 0 && @$questionV['child_question']) {
                        $questionCount = count($questionV['child_question']);
                        $isUpWeight = isset($questionV['is_up_weight']) ? $questionV['is_up_weight'] : true; // 前端传值true或false 未传默认true排序
                        foreach ($questionV['child_question'] as $questionK2 => $questionV2) {
                            $questionId = $questionV2['question_id'];
                            $questionV2['template_id'] = $template_id;
                            $questionV2['database_id'] = $database_id;
                            $questionV2['item_id']     = $itemId;
                            $questionV2['usercare_id'] = $usercare_id;
                            $questionV2['parent_id']   = $firstQuestionId;
                            if ($isUpWeight) $questionV2['weight'] = $questionCount;
                            # 新增变量组/一级变量 含新增选项
                            if (!$questionId) $questionId = $questionModel->createQuestion($questionV2);
                            if (!$questionId) return 26;
                            $questionV2['question_id'] = $questionId;

                            if (!$questionV2['relation_id']) {
                                # 新增二级变量关联 含新增关联选项
                                $relation_id = $relationQuestionModel->createRelationQuestion($questionV2);
                                if (!$relation_id) return 27;
                            }else{
                                # 编辑变量 含关联变量及选项即关联选项
                                $saveQuestion = $relationQuestionModel->saveQuestion($template_id,$questionId,$questionV2,$usercare_id);
                                if (!$saveQuestion) return 28;
                            }
                            $questionCount--;
                        }
                    }
                }
            }
        }        
        return true;
    }
    /**
     * 删除模板下item及question
     * template_id 模板id
     * delArr      删除的数组 item_arr=>删除的item_id question_arr=>删除的question_id
     * MSQ 2021-8-16
     */
    public function deleteItemAndQuestion($template_id = 0,$delArr = [])
    {
        if (!$delArr) return true;
        if (!$template_id) return false;

        # 总库下引用该目录/模块的子库模板
        $relevantTemplateId = $this->getChildDbOrTemplate($template_id,2);
        $relevantTemplateId = array_filter($relevantTemplateId);
        if (!$relevantTemplateId) return false;

        $saveData = ['status' => 0];
        if ($delArr['item_arr']) {
            # 删除相关模板下item
            # 更新relationItem
            $where = [
                'item_id'     => ['IN',$delArr['item_arr']],
                'template_id' => ['IN',$relevantTemplateId],
                'status'      => 1
            ];
            $saveRes = model('DbTemplateRelationItem')->update($saveData,$where);
            if (!$saveRes) return false;

            $where['template_id'] = ['NOT IN',$relevantTemplateId];
            # 有跨总库的item
            $hasOtherSync = model('DbTemplateRelationItem')->where($where)->group('item_id')->column('item_id');
            # 取差集 即没有跨总库关联的模块
            $deletePub = array_diff($delArr['item_arr'],$hasOtherSync);
            if ($deletePub) {
                # 同步修改item表数据
                $saveRes = model('DbItem')->update($saveData,['id' => ['IN',$deletePub],'status' => 1]);
                if (!$saveRes) return false;
            }
            # 注：此处不考虑同步删除下级模块&变量&回答 调用此方法前会进行数据验证，确保没有下级
        }
        if ($delArr['question_arr']) {
            # 删除相关模板下item
            # 更新relationItem
            $where = [
                'question_id' => ['IN',$delArr['question_arr']],
                'template_id' => ['IN',$relevantTemplateId],
                'status'      => 1
            ];
            $saveRes = model('DbTemplateRelationQuestion')->update($saveData,$where);
            if (!$saveRes) return false;

            # 删除关联选项
            $saveRes = model('DbTemplateRelationQuestionOption')->update($saveData,$where);
            if (!$saveRes) return false;

            $where['template_id'] = ['NOT IN',$relevantTemplateId];
            # 有跨总库的item
            $hasOtherSync = model('DbTemplateRelationQuestion')->where($where)->group('question_id')->column('question_id');
            # 取差集 即没有跨总库关联的模块
            $deletePub = array_diff($delArr['question_arr'],$hasOtherSync);
            if ($deletePub) {
                # 同步修改变量总表数据
                $saveRes = model('DbQuestion')->update($saveData,['id' => ['IN',$deletePub],'status' => 1]);
                if (!$saveRes) return false;
                # 同步修改选项总表数据
                $saveRes = model('DbQuestionOption')->update($saveData,['question_id' => ['IN',$deletePub],'status' => 1]);
                if (!$saveRes) return false;
            }
            # 注：此处不考虑同步删除相关二级变量及回答 调用此方法前会进行数据验证，存在回答的不允许删除
        }
        # 清除模板变量列表缓存
        $this->clearTemplateQueationRedis($template_id,1);
        
        return true;
    }
    /**
     * 删除数据库模板
     * @param int  $database_id 数据库id
     * @author MSQ 2021-8-21
     */
    public function deleteDbTemplate($databaseInfo = [])
    {
        if (!is_array($databaseInfo)) $databaseInfo = model('DbDatabase')->getDetails($databaseInfo);
        if (!$databaseInfo) return false;

        $relevantData = @$databaseInfo['relevantData'];
        # 相关数据库及模板 含子库 模板=>数据库
        if (!$relevantData) return true;
        # 相关模板
        $relevantTemplateId = array_filter(array_keys($relevantData));
        if (!$relevantTemplateId) return true;

        # 删除模板关联模块
        $res = model('DbTemplateRelationItem')->deleteDataByTemplate($relevantTemplateId);
        if (!$res) return false;

        # 删除模板关联变量
        $res = model('DbTemplateRelationQuestion')->deleteDataByTemplate($relevantTemplateId);
        
        # 删除模板关联选项
        $res = model('DbTemplateRelationQuestionOption')->deleteDataByTemplate($relevantTemplateId);
        if (!$res) return false;

        # 删除数据库模板数据
        $res = $this->deleteTemplateData($relevantTemplateId);
        if (!$res) return false;

        # 清除模板变量列表缓存
        $this->clearTemplateQueationRedis($relevantTemplateId,1);
        
        return true;
    }
    /**
     * 删除模板数据
     * @param int  $template_id 模板id 可为数组 删除总库时同步删除子库
     * @author MSQ 2021-8-21
     */
    public function deleteTemplateData($template_id = [])
    {
        if (!$template_id) return false;
        if (!is_array($template_id)) $template_id = [$template_id];

        $where = [
            'status' => 1,
            'id'     => ['IN',$template_id]
        ];
        $res = $this->update(['status' => 0,'is_use' => 0],$where);
        if (!$res) return false;
        return true;
    }
    # --------------------------------- 数据处理类接口 END ----------------------------------

}
